﻿using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.Timeline;

namespace GameToolkit
{
    [TrackBindingType(typeof(Light))]
    [TrackColor(0.1f, 0.7f, 1f)]
    [TrackClipType(typeof(LightingClip))]
    public class LightingTrack : TrackAsset
    {
        [SerializeField, Tooltip("勾选时 Timeline 播放结束后保持灯光状态，否则回复播放前状态")]
        bool m_KeepLightState;

        public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
        {
            var playable = ScriptPlayable<LightingBehaviour>.Create(graph, inputCount);
            var behaviour = playable.GetBehaviour();
            behaviour.mKeepState = m_KeepLightState;
            PlayableDirector dir;
            if (go.TryGetComponent(out dir))
            {
                var light = dir.GetGenericBinding(this) as Light;
                if (light != null)
                {
                    behaviour.InitState(light);
                }
            }
            return playable;
        }

        public class LightingBehaviour : PlayableBehaviour
        {
            internal bool mKeepState;
            Color mStartColor;
            float mStartIntensity;
            float mStartShadow;
            Light mStartLight;

            ColorParameter mColor = new ColorParameter(Color.white);
            FloatParameter mIntensity = new FloatParameter(1);
            FloatParameter mShadow = new FloatParameter(1);

            internal void InitState(Light light)
            {
                mStartLight = light;
                mStartColor = light.color;
                mStartIntensity = light.intensity;
                mStartShadow = light.shadowStrength;
            }

            void Override<T>(VolumeParameter<T> newValue, VolumeParameter<T> dest, float t)
            {
                if (newValue.overrideState)
                {
                    dest.Interp(dest.value, newValue.value, t);
                    dest.overrideState = true;
                }
            }

            public void Override(LightingClip lightData, float weight)
            {
                Override(lightData.color, mColor, weight);
                Override(lightData.intensity, mIntensity, weight);
                Override(lightData.shadowStrength, mShadow, weight);
            }

            public override void PrepareFrame(Playable playable, FrameData info)
            {
                mColor.overrideState = false;
                mColor.value = mStartColor;
                mIntensity.overrideState = false;
                mIntensity.value = mStartIntensity;
                mShadow.overrideState = false;
                mShadow.value = mStartShadow;
            }

            public override void OnGraphStop(Playable playable)
            {
                if (!mKeepState && mStartLight != null)
                {
                    mStartLight.color = mStartColor;
                    mStartLight.intensity = mStartIntensity;
                    mStartLight.shadowStrength = mStartShadow;
                }
            }

            public override void ProcessFrame(Playable playable, FrameData info, object playerData)
            {
                var light = playerData as Light;
                if (light == null)
                    return;
                var isStartLight = light == mStartLight;
                if (mColor.overrideState || isStartLight)
                    light.color = mColor.value;
                if (mIntensity.overrideState || isStartLight)
                    light.intensity = mIntensity.value;
                if (mShadow.overrideState || isStartLight)
                    light.shadowStrength = mShadow.value;
            }
        }
    }
}
